package groep1.graph;

import groep1.ObjectList;
import groep1.graph.dialog.HelpDialog;
import groep1.graph.graphstrategy.layout.CircularLayoutStrategy;
import groep1.graph.graphstrategy.layout.GraphPlacementStrategy;
import groep1.graph.graphstrategy.layout.GridLayoutStrategy;
import groep1.graph.graphstrategy.line.LineStrategy;
import groep1.graph.graphstrategy.line.NaiveLineStrategy;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;

/**
 * A frame which displays the graph of all the objects with the references to
 * other objects.
 * 
 * @author Niels Billen, Jorn Van Loock
 * @version 0.1
 * @since 0.1
 */
public class GraphFrame extends JFrame implements WindowListener {

	public JTextField inputField = new JTextField(); // The inputfield with the
														// filterRegex

	/**
	 * Creates a new frame displaying the graph with the object and the
	 * references between them.
	 * 
	 * @param x
	 *            The x position of the frame on the screen.
	 * @param y
	 *            The y position of the frame on the screen.
	 * @param width
	 *            The width of the frame.
	 * @param height
	 *            The height of the frame.
	 * @throws IllegalArgumentException
	 *             When the given width or height is smaller than zero.
	 */
	private GraphFrame(int x, int y, int width, int height)
			throws IllegalArgumentException {
		super("Graph editor");

		// Set the size
		setLocation(x, y);
		setFocusable(true);
		setIgnoreRepaint(false);
		setBackground(Color.WHITE);

		// Create the content
		createContent(getContentPane());

		pack();
		setVisible(true);
		repaint();

		addWindowListener(this);
	}

	/**
	 * Creates the content.
	 * 
	 * @param c
	 *            The container to add.
	 * @throws NullPointerException
	 *             When the given container is null.
	 */
	private void createContent(Container c) {
		if (c == null)
			throw new NullPointerException("The given container is null!");

		GraphPlacementStrategy placementStrategy = new GridLayoutStrategy(4, 4,
				64, 64, 0, 0, 0, 0, false);
		LineStrategy lineStrategy = new NaiveLineStrategy();
		graphComponent = new GraphComponent(placementStrategy, lineStrategy);

		JScrollPane scroller = new JScrollPane(graphComponent);
		scroller.setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));

		c.add(createFilterPanel(), BorderLayout.PAGE_START);
		c.add(scroller, BorderLayout.CENTER);
	}

	/**
	 * Creates the filter panel.
	 * 
	 * @return the filter panel.
	 */
	public JPanel createFilterPanel() {
		JPanel result = new JPanel(new BorderLayout());

		// The label with displaying that you can change the layout.
		JLabel layoutLabel = new JLabel("Layout: ");
		layoutLabel.setHorizontalAlignment(SwingConstants.LEFT);

		// Button to change to a grid layout
		JButton gridButton = new JButton("Grid layout");
		gridButton.setVerticalAlignment(SwingConstants.CENTER);
		gridButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				GraphPlacementStrategy c = new GridLayoutStrategy(4, 4, 64, 64,
						64, 64, 0, 0, false);
				graphComponent.setGraphPlacementStrategy(c);
				graphComponent.revalidate();
				graphComponent.repaint();
				graphComponent.layout(graphComponent.getGraphObjects());
			}
		});

		// Button to change to a circular layout
		JButton circularButton = new JButton("Circular layout");
		circularButton.setVerticalAlignment(SwingConstants.CENTER);
		circularButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				GraphPlacementStrategy c = new CircularLayoutStrategy();
				graphComponent.setGraphPlacementStrategy(c);
				graphComponent.revalidate();
				graphComponent.repaint();
				graphComponent.layout(graphComponent.getGraphObjects());
			}
		});

		JLabel filterLabel = new JLabel("Filter: ");
		filterLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		filterLabel.setVerticalAlignment(SwingConstants.CENTER);

		// final JTextField inputField = new JTextField(); //TODO: mag da zomaar
		// final?
		inputField.setText("");
		inputField.setPreferredSize(new Dimension(256, 24));

		JButton filterButton = new JButton("Filter!");
		filterButton.setVerticalAlignment(SwingConstants.CENTER);
		filterButton.setPreferredSize(getPreferredSize());
		filterButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				GraphFrame.getInstance().applyFilter();
			}
		});

		JButton helpButton = new JButton("Help");
		helpButton.setVerticalAlignment(SwingConstants.CENTER);
		helpButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JDialog dialog = HelpDialog.getInstance();
				dialog.setVisible(true);
			}
		});

		JPanel layoutPanel = new JPanel(new FlowLayout());
		layoutPanel.add(layoutLabel);
		layoutPanel.add(gridButton);
		layoutPanel.add(circularButton);

		SpringLayout layout = new SpringLayout();
		JPanel filterPanel = new JPanel(layout);
		filterPanel.add(filterLabel);
		filterPanel.add(inputField);
		filterPanel.add(filterButton);

		layout.putConstraint(SpringLayout.WEST, filterLabel, 0,
				SpringLayout.WEST, filterPanel);
		layout.putConstraint(SpringLayout.NORTH, filterLabel, 0,
				SpringLayout.NORTH, filterPanel);
		layout.putConstraint(SpringLayout.SOUTH, filterLabel, 0,
				SpringLayout.SOUTH, filterPanel);

		layout.putConstraint(SpringLayout.WEST, inputField, 0,
				SpringLayout.EAST, filterLabel);
		layout.putConstraint(SpringLayout.NORTH, inputField, 4,
				SpringLayout.NORTH, filterLabel);
		layout.putConstraint(SpringLayout.SOUTH, inputField, -4,
				SpringLayout.SOUTH, filterLabel);
		layout.putConstraint(SpringLayout.EAST, inputField, -100,
				SpringLayout.EAST, filterPanel);

		layout.putConstraint(SpringLayout.WEST, filterButton, 4,
				SpringLayout.EAST, inputField);
		layout.putConstraint(SpringLayout.NORTH, filterButton, 5,
				SpringLayout.NORTH, filterLabel);
		layout.putConstraint(SpringLayout.SOUTH, filterButton, -5,
				SpringLayout.SOUTH, filterLabel);
		layout.putConstraint(SpringLayout.EAST, filterButton, 0,
				SpringLayout.EAST, filterPanel);

		JPanel helpPanel = new JPanel(new FlowLayout());
		helpPanel.add(helpButton);

		result.add(layoutPanel, BorderLayout.WEST);
		result.add(filterPanel, BorderLayout.CENTER);
		result.add(helpPanel, BorderLayout.EAST);

		return result;
	}

	/**
	 * Applies the filter.
	 */
	public void applyFilter() {
		graphComponent.setDisplayObjects(ObjectList.getInstance().filter(
				inputField.getText()));
		setVisible(true);
	}

	/**
	 * Starts this graph frame.
	 * 
	 * @param arguments
	 *            The arguments from the command line.
	 */
	public static void main(String[] args) {
		getInstance();
	}

	/**
	 * Returns the singleton instance of this graph frame.
	 * 
	 * @return the singleton instance of this graph frame.
	 */
	public static GraphFrame getInstance() {
		if (frame == null)
			frame = new GraphFrame(64, 64, 640, 480);
		return frame;
	}

	private static GraphFrame frame;

	/**
	 * Returns the graph component.
	 * 
	 * @return the graph component.
	 */
	public GraphComponent getGraphComponent() {
		return graphComponent;
	}

	/**
	 * Returns the graph component.
	 */
	private GraphComponent graphComponent;

	/**
	 * The default width and height
	 */
	public static final int DEFAULT_WIDTH = 640;

	/**
	 * The default height.
	 */
	public static final int DEFAULT_HEIGHT = 480;

	/**
	 * An ID for serialization.
	 */
	private static final long serialVersionUID = -6794981117159005330L;

	@Override
	public void windowActivated(WindowEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosed(WindowEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowClosing(WindowEvent e) {
		setVisible(false);

	}

	@Override
	public void windowDeactivated(WindowEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowDeiconified(WindowEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowIconified(WindowEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void windowOpened(WindowEvent e) {
		// TODO Auto-generated method stub

	}
}
